﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Reflection;
using System.Windows.Documents;
using System.Windows.Markup;
using System.Windows.Media;
using System.Windows;
using System.Windows.Controls;

namespace PrintManager
{
    public class PrintEngine
    {
        static List<PaperDefinition> _papers;
        static List<LayoutDefinition> _layouts;

        public PrintEngine()
        {
            if (_papers == null || _layouts == null)
            {
                string path = System.IO.Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
                DirectoryInfo dir = new DirectoryInfo(path + "\\Data");
                _papers = (from p in dir.GetFiles("*.paper") select PaperDefinition.Load(p.FullName)).ToList();
                _layouts = (from l in dir.GetFiles("*.layout") select LayoutDefinition.Load(l.FullName)).ToList();
            }
        }

        public List<LayoutDefinition> LayoutsForReport( string reportId, object data = null )
        {
            var list = _layouts.Where(x => x.Reports.Contains(reportId)).ToList();
            foreach (var t in list)
                foreach (var e in t.Elements)
                    e.NewValue().DataContext = data;
            return list;
        }

        public List<PaperDefinition> PapersForLayout( LayoutDefinition layout )
        {
            return _papers.Where(p => layout.Papers.Contains(p.Id)).ToList();
        }

        double points(double cm)
        {
            return cm * 96.0 / 2.54;
        }

        public FixedPage NewPage(Size size)
        {
            FixedPage page = new FixedPage();
            page.Width = size.Width;
            page.Height = size.Height;
            return page;
        }

        public void AddPage(FixedDocument document, FixedPage page)
        {
            Size size = document.DocumentPaginator.PageSize;
            page.Measure(size);
            page.Arrange(new Rect(new Point(), size));
            page.UpdateLayout();

            PageContent pageContent = new PageContent();
            ((IAddChild)pageContent).AddChild(page);
            document.Pages.Add(pageContent);
        }

        public FixedDocument CreateDocument(List<object> data, LayoutDefinition layout, PaperDefinition paper)
        {
            FixedDocument document = new FixedDocument();
            document.DocumentPaginator.PageSize = new Size(points(paper.Width), points(paper.Height));

            FixedPage page = NewPage(document.DocumentPaginator.PageSize);

            double scale = 96.0 / 2.54;

            var elements = paper.Elements.OrderBy(x => x.X).ThenBy(x => x.Y).ToList();

            int ix = 0;
            foreach (object x in data)
            {
                if (ix >= elements.Count())
                {
                    ix = 0;
                    AddPage(document, page);
                    page = NewPage(document.DocumentPaginator.PageSize);
                }
                PaperElement pe = elements.ElementAt(ix);
                
                //string lay = layout.Elements[pe.ID];
                //FrameworkElement e = (FrameworkElement)XamlReader.Parse(lay);
                LayoutElement lay = layout.Elements.Where( t => t.Id == pe.ID ).FirstOrDefault();
                FrameworkElement e = lay.NewValue();
                if (e != null)
                {
                    e.DataContext = x;
                    e.RenderTransform = new ScaleTransform { ScaleX = scale, ScaleY = scale };
                    FixedPage.SetLeft(e, points(pe.X));
                    FixedPage.SetTop(e, points(pe.Y));
                    page.Children.Add(e);
                }
                ix++;
            }

            if (ix > 0 )
                AddPage(document, page);

            return document;
        }
    }
}
